package com.peak.distribution.service.agent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.peak.distribution.entity.agent.DisAgent;
import com.peak.distribution.entity.agent.DisAgentTeam;
import com.peak.distribution.entity.order.DisOrder;
import com.peak.distribution.entity.order.DisOrderGoods;
import com.peak.distribution.entity.sales.DisAgentSalesDayLog;
import com.peak.distribution.entity.sales.DisAgentSalesMonthLog;
import com.peak.distribution.entity.sales.DisAgentSalesQuarterLog;
import com.peak.distribution.entity.sales.DisAgentSalesWeekLog;
import com.peak.distribution.enums.OrderStatus;
import com.peak.distribution.manager.agent.DisAgentTeamManager;
import com.peak.distribution.manager.order.DisOrderManager;
import com.peak.distribution.manager.sales.DisAgentSalesDayLogManager;
import com.peak.distribution.manager.sales.DisAgentSalesMonthLogManager;
import com.peak.distribution.manager.sales.DisAgentSalesQuarterLogManager;
import com.peak.distribution.manager.sales.DisAgentSalesWeekLogManager;
import com.peak.spring.boot.api.repository.FilterParam;
import com.peak.spring.boot.builder.repository.FilterParamBuilder;
import com.peak.spring.boot.tools.DatePattern;
import com.peak.spring.boot.tools.Dates;

import lombok.extern.slf4j.Slf4j;

@Transactional
@Service
@Slf4j
public class DisAgentSalesServiceImpl implements DisAgentSalesService {
	
	@Autowired
	private DisOrderManager orderManager;
	
	@Autowired
	private DisAgentSalesDayLogManager agentSalesDayLogManager;
	
	@Autowired
	private DisAgentSalesWeekLogManager agentSalesWeekLogManager;
	
	@Autowired
	private DisAgentSalesMonthLogManager agentSalesMonthLogManager;
	
	@Autowired
	private DisAgentSalesQuarterLogManager agentSalesQuarterLogManager;
	
	@Autowired
	private DisAgentTeamManager agentTeamManager;

	@Override
	public void statisticsSalesLog() {
		// 把生成订单的状态统计出来
		String statuses = Arrays.stream(OrderStatus.values()).filter(p -> {
			switch (p) {
			case SHIPPED:
			case SUCCEED:
				return true;
			default:
				return false;
			}
		}).map(p -> p.name()).collect(Collectors.joining(","));
		// 计算时间
		Date now = Dates.now();
		Date startDate = Dates.clearTime(Dates.addDay(now, -1));
		Date endDate = Dates.lastScend(Dates.addDay(now, -1));
		log.info("订单统计的时间{}~{}", Dates.format(startDate, DatePattern.SHORT_LINE_TIME), Dates.format(endDate, DatePattern.SHORT_LINE_TIME));
		
		// 查询条件
		List<FilterParam> filters = FilterParamBuilder.create()
				.in("status", statuses) // 状态必须是已付款之后的情况
				.gte("orderTime", startDate) // 时间是上一天的0点
				.lte("orderTime", endDate) // 结束是上一天的23点
				.build();
		List<DisOrder> orders = orderManager.findList(filters);
		log.info("昨日成交订单{}比", orders.size());
		Map<DisAgent, List<DisOrder>> map = orders.stream().collect(Collectors.groupingBy(DisOrder::getAgent));
		log.info("有{}个代理商实现销售", map.size());
		List<DisAgentSalesDayLog> agentDayLogs = Lists.newArrayList();
		Map<DisAgentTeam, DisAgentSalesDayLog> teamMap = Maps.newHashMap();
		for (Entry<DisAgent, List<DisOrder>> entry : map.entrySet()) {
			// key就是代理商
			DisAgent agent = entry.getKey();
			// value就是代理商的订单列表
			List<DisOrder> agentOrders = entry.getValue();
			// 直接统计订单的金额
			int goodsNum = 0;
			int amount = 0;
			for (DisOrder order : agentOrders) {
				amount += order.getGoodsFee();
				for (DisOrderGoods goods : order.getGoodses()) {
					goodsNum += goods.getQuantity();
				}
			}
			// 新增一条代理商的销量统计
			DisAgentSalesDayLog agentDayLog = new DisAgentSalesDayLog();
			agentDayLog.setOrderNum(agentOrders.size());
			agentDayLog.setAmount(amount);
			agentDayLog.setGoodsNum(goodsNum);
			agentDayLog.setAgent(agent);
			agentDayLog.setSalesDate(startDate);
			agentDayLogs.add(agentDayLog);
			// 代理商所属的所有团队
			List<DisAgentTeam> teams = agentTeamManager.getAllTeam(agent);
			for (DisAgentTeam team : teams) {
				DisAgentSalesDayLog teamDayLog = teamMap.get(team);
				if (teamDayLog == null) {
					teamDayLog = new DisAgentSalesDayLog();
					teamMap.put(team, teamDayLog);
					teamDayLog.setTeam(team);
					teamDayLog.setSalesDate(startDate);
				}
				// 累计销量和订单数量
				teamDayLog.addOrderNum(agentOrders.size());
				teamDayLog.addAmount(amount);
				teamDayLog.addGoodsNum(goodsNum);
			}
		}
		List<DisAgentSalesDayLog> teamDayLogs = new ArrayList<>(teamMap.values());
		// 保存代理商的销量
		agentSalesDayLogManager.save(agentDayLogs);
		// 保留团队的销量
		agentSalesDayLogManager.save(teamDayLogs);
		log.info("昨日销量统计结束");
		statisticsSalesWeekLog(agentDayLogs, teamDayLogs);
		log.info("本周销量统计结束");
		statisticsSalesMonthLog(agentDayLogs, teamDayLogs);
		log.info("本月销量统计结束");
		statisticsSalesQuarterLog(agentDayLogs, teamDayLogs);
		log.info("本季度销量统计结束");
	}

	@Override
	public void statisticsSalesWeekLog(List<DisAgentSalesDayLog> agentDayLogs, List<DisAgentSalesDayLog> teamDayLogs) {
		Calendar week = Calendar.getInstance();
		// 个人周销量
		List<DisAgentSalesWeekLog> agentWeekLogs = agentSalesWeekLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", week.get(Calendar.YEAR))
				.eq("salesMonth", week.get(Calendar.MONTH))
				.eq("salesWeek", week.get(Calendar.WEEK_OF_MONTH))
				.notnull("agent.id")
				.isnull("team.id")
				.build());
		Map<DisAgent, DisAgentSalesWeekLog> agentWeekLogMap = agentWeekLogs.stream().collect(Collectors.toMap(DisAgentSalesWeekLog::getAgent, p -> p));
		for (DisAgentSalesDayLog dayLog : agentDayLogs) {
			DisAgent agent = dayLog.getAgent();
			DisAgentSalesWeekLog weekLog = agentWeekLogMap.get(agent);
			if (weekLog == null) {
				weekLog = new DisAgentSalesWeekLog();
				weekLog.setAgent(agent);
				weekLog.setSalesYear(week.get(Calendar.YEAR));
				weekLog.setSalesMonth(week.get(Calendar.MONTH));
				weekLog.setSalesWeek(week.get(Calendar.WEEK_OF_MONTH));
				agentWeekLogMap.put(agent, weekLog);
			}
			weekLog.addAmount(dayLog.getAmount());
			weekLog.addOrderNum(dayLog.getOrderNum());
			weekLog.addGoodsNum(dayLog.getGoodsNum());
		}
		
		// 团队周销量统计
		List<DisAgentSalesWeekLog> teamWeekLogs = agentSalesWeekLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", week.get(Calendar.YEAR))
				.eq("salesMonth", week.get(Calendar.MONTH) + 1)
				.eq("salesWeek", week.get(Calendar.WEEK_OF_MONTH))
				.isnull("agent.id")
				.notnull("team.id")
				.build());
		Map<DisAgentTeam, DisAgentSalesWeekLog> teamWeekLogMap = teamWeekLogs.stream().collect(Collectors.toMap(DisAgentSalesWeekLog::getTeam, p -> p));
		for (DisAgentSalesDayLog dayLog : teamDayLogs) {
			DisAgentTeam team = dayLog.getTeam();
			DisAgentSalesWeekLog weekLog = teamWeekLogMap.get(team);
			if (weekLog == null) {
				weekLog = new DisAgentSalesWeekLog();
				weekLog.setTeam(team);
				weekLog.setSalesYear(week.get(Calendar.YEAR));
				weekLog.setSalesMonth(week.get(Calendar.MONTH) + 1);
				weekLog.setSalesWeek(week.get(Calendar.WEEK_OF_MONTH));
				teamWeekLogMap.put(team, weekLog);
			}
			weekLog.addAmount(dayLog.getAmount());
			weekLog.addOrderNum(dayLog.getOrderNum());
			weekLog.addGoodsNum(dayLog.getGoodsNum());
		}
		
		agentSalesWeekLogManager.save(agentWeekLogMap.values());
		agentSalesWeekLogManager.save(teamWeekLogMap.values());
	}

	@Override
	public void statisticsSalesMonthLog(List<DisAgentSalesDayLog> agentDayLogs, List<DisAgentSalesDayLog> teamDayLogs) {
		Calendar month = Calendar.getInstance();
		
		List<DisAgentSalesMonthLog> agentMonthLogs = agentSalesMonthLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", month.get(Calendar.YEAR))
				.eq("salesMonth", month.get(Calendar.MONTH))
				.notnull("agent.id")
				.isnull("team.id")
				.build());
		Map<DisAgent, DisAgentSalesMonthLog> agentMonthLogMap = agentMonthLogs.stream().collect(Collectors.toMap(DisAgentSalesMonthLog::getAgent, p -> p));
		for (DisAgentSalesDayLog dayLog : agentDayLogs) {
			DisAgent agent = dayLog.getAgent();
			DisAgentSalesMonthLog monthLog = agentMonthLogMap.get(agent);
			if (monthLog == null) {
				monthLog = new DisAgentSalesMonthLog();
				monthLog.setAgent(agent);
				monthLog.setSalesYear(month.get(Calendar.YEAR));
				monthLog.setSalesMonth(month.get(Calendar.MONTH));
				agentMonthLogMap.put(agent, monthLog);
			}
			monthLog.addAmount(dayLog.getAmount());
			monthLog.addOrderNum(dayLog.getOrderNum());
			monthLog.addGoodsNum(dayLog.getGoodsNum());
		}
		// 团队周销量统计
		
		List<DisAgentSalesMonthLog> teamMonthLogs = agentSalesMonthLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", month.get(Calendar.YEAR))
				.eq("salesMonth", month.get(Calendar.MONTH) + 1)
				.isnull("agent.id")
				.notnull("team.id")
				.build());
		Map<DisAgentTeam, DisAgentSalesMonthLog> teamMonthLogMap = teamMonthLogs.stream().collect(Collectors.toMap(DisAgentSalesMonthLog::getTeam, p -> p));
		for (DisAgentSalesDayLog dayLog : teamDayLogs) {
			DisAgentTeam team = dayLog.getTeam();
			DisAgentSalesMonthLog weekLog = teamMonthLogMap.get(team);
			if (weekLog == null) {
				weekLog = new DisAgentSalesMonthLog();
				weekLog.setTeam(team);
				weekLog.setSalesYear(month.get(Calendar.YEAR));
				weekLog.setSalesMonth(month.get(Calendar.MONTH) + 1);
				teamMonthLogMap.put(team, weekLog);
			}
			weekLog.addAmount(dayLog.getAmount());
			weekLog.addOrderNum(dayLog.getOrderNum());
			weekLog.addGoodsNum(dayLog.getGoodsNum());
		}
		
		agentSalesMonthLogManager.save(agentMonthLogMap.values());
		agentSalesMonthLogManager.save(teamMonthLogMap.values());
	}

	@Override
	public void statisticsSalesQuarterLog(List<DisAgentSalesDayLog> agentDayLogs, List<DisAgentSalesDayLog> teamDayLogs) {
		Calendar quarter = Calendar.getInstance();
		int currentQuarter = (int) Math.ceil((double)(quarter.get(Calendar.MONTH) + 1) / 3);
		
		List<DisAgentSalesQuarterLog> agentQuarterLogs = agentSalesQuarterLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", quarter.get(Calendar.YEAR))
				.eq("salesQuarter", currentQuarter)
				.notnull("agent.id")
				.isnull("team.id")
				.build());
		Map<DisAgent, DisAgentSalesQuarterLog> agentQuarterLogMap = agentQuarterLogs.stream().collect(Collectors.toMap(DisAgentSalesQuarterLog::getAgent, p -> p));
		for (DisAgentSalesDayLog dayLog : agentDayLogs) {
			DisAgent agent = dayLog.getAgent();
			DisAgentSalesQuarterLog quarterLog = agentQuarterLogMap.get(agent);
			if (quarterLog == null) {
				quarterLog = new DisAgentSalesQuarterLog();
				quarterLog.setAgent(agent);
				quarterLog.setSalesYear(quarter.get(Calendar.YEAR));
				quarterLog.setSalesQuarter(currentQuarter);
				agentQuarterLogMap.put(agent, quarterLog);
			}
			quarterLog.addAmount(dayLog.getAmount());
			quarterLog.addOrderNum(dayLog.getOrderNum());
			quarterLog.addGoodsNum(dayLog.getGoodsNum());
		}
		// 团队周销量统计
		
		List<DisAgentSalesQuarterLog> teamQuarterLogs = agentSalesQuarterLogManager.findList(FilterParamBuilder.create()
				.eq("salesYear", quarter.get(Calendar.YEAR))
				.eq("salesQuarter", currentQuarter)
				.isnull("agent.id")
				.notnull("team.id")
				.build());
		Map<DisAgentTeam, DisAgentSalesQuarterLog> teamQuarterLogMap = teamQuarterLogs.stream().collect(Collectors.toMap(DisAgentSalesQuarterLog::getTeam, p -> p));
		for (DisAgentSalesDayLog dayLog : teamDayLogs) {
			DisAgentTeam team = dayLog.getTeam();
			DisAgentSalesQuarterLog quarterLog = teamQuarterLogMap.get(team);
			if (quarterLog == null) {
				quarterLog = new DisAgentSalesQuarterLog();
				quarterLog.setTeam(team);
				quarterLog.setSalesYear(quarter.get(Calendar.YEAR));
				quarterLog.setSalesQuarter(currentQuarter);
				teamQuarterLogMap.put(team, quarterLog);
			}
			quarterLog.addAmount(dayLog.getAmount());
			quarterLog.addOrderNum(dayLog.getOrderNum());
			quarterLog.addGoodsNum(dayLog.getGoodsNum());
		}
		
		agentSalesQuarterLogManager.save(agentQuarterLogMap.values());
		agentSalesQuarterLogManager.save(teamQuarterLogMap.values());
	}

}
